package es.wtestgen.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import es.wtestgen.bean.profesor.ExamenForm;
import es.wtestgen.domain.Asignatura;
import es.wtestgen.domain.Examen;
import es.wtestgen.domain.Pregunta;
import es.wtestgen.domain.Respuesta;
import es.wtestgen.services.AsignaturaDAO;
import es.wtestgen.services.PreguntaDAO;
import es.wtestgen.services.RespuestaDAO;

public class EstrategiaGeneraExamenByPaso2 implements
		EstrategiaGeneraExamen {

	public EstrategiaGeneraExamenByPaso2()	{
		
	}
	
	public ExamenForm generaExamen(ExamenForm examen) {
			
		RespuestaDAO respuestaDao = new RespuestaDAO();
		AsignaturaDAO asignaturaDao = new AsignaturaDAO();
		PreguntaDAO preguntaDao = new PreguntaDAO();
		
		int codAsig = examen.getCodAsig();
		Asignatura asignatura = (Asignatura)asignaturaDao.findById(String.valueOf(codAsig)).get(0);
		
		/*
		 * Obtenemos todas las preguntas de la asignatura 
		 */
		List<Pregunta> preguntas = preguntaDao.findPreguntasAsignatura(asignatura);
		
		/*
		 * Si tenemos menos preguntas que las que se piden para generar el examen
		 * entonces modificamos el numero de preguntas con el total de las que tengamos
		 * disponibles
		 */
		
		if(examen.getNumPreg() > preguntas.size()){
			examen.setNumPreg(preguntas.size());
		}		
		

		/*
		 * Generamos aleatoriamente el numero de preguntas
		 */
		
		Random rand = new Random();
			
		/*
		 * Generamos aleatoriamente la dificultad del examen ya que nos llegara vacia
		 */
		
		double random = Math.random();
		if(random <= 0.33){
			examen.setDificultadExamen("Baja");
		}else if(random > 0.33 && random <= 0.66){
			examen.setDificultadExamen("Media");				
		}else{
			examen.setDificultadExamen("Alta");
		}
		
		
		Map<String, Pregunta> mapaPreguntas = new HashMap<String, Pregunta>(preguntas.size());
		
		for (Iterator iterator = preguntas.iterator(); iterator.hasNext();) {
			Pregunta pregunta = (Pregunta) iterator.next();
			
			/*
			 * Nuestro examen en funcion de la dificultad se basara en torno a los siguientes valores:
			 * 
			 * 	Baja 	=>	dificultad = 1 o 2
			 * 	Media	=>	dificultad = 3 o 4
			 * 	Alta	=>	dificultad = 5 o 6
			 */
			
			if(examen.getDificultadExamen().equals("Baja")){
				if(pregunta.getDificultad() == 1 || pregunta.getDificultad() == 2){
					mapaPreguntas.put(String.valueOf(pregunta.getCodPreg()), pregunta);
				}
			}else if(examen.getDificultadExamen().equals("Media")){
				if(pregunta.getDificultad() == 3 || pregunta.getDificultad() == 4){
					mapaPreguntas.put(String.valueOf(pregunta.getCodPreg()), pregunta);					
				}
			}else if(examen.getDificultadExamen().equals("Alta")){
				if(pregunta.getDificultad() == 5 || pregunta.getDificultad() == 6){
					mapaPreguntas.put(String.valueOf(pregunta.getCodPreg()), pregunta);
				}
			}		
			
		}
		
		/*
		 * Si no tenemos preguntas suficientes de la dificultad exigida para completar el numero total de preguntas del examen 
		 * entonces se anade cualquier pregunta que vayamos recuperando siempre que no se haya anadido anteriormente sea cual sea
		 * su nivel de dificultad	 
		 */
		if(mapaPreguntas.size() < examen.getNumPreg()){
			
			//LANZAMOS UNA EXCEPCION O UN ERROR O LE INDICAMOS AL USUARIO DE ALGUNA FORMA QUE CON EL SISTEMA ACTUAL NO SE 
			//PUEDEN CUMPLIR LOS REQUISITOS PARA GENERAR EL EXAMEN AUTOMATICAMENTE
			
			int t = mapaPreguntas.size();
			
			while(t < examen.getNumPreg()){
				int ind = (int)(rand.nextDouble() * preguntas.size());
				Pregunta p = (Pregunta) preguntas.get(ind);
				if(!mapaPreguntas.containsKey(String.valueOf(p.getCodPreg()))){
					mapaPreguntas.put(String.valueOf(p.getCodPreg()), p);	
					t++;
				}				
			}
			
		}
		
		
		/*
		 * Guardamos en un array de enteros todos los codigos de las preguntas para poder buscar aleatoriamente las que cumplen
		 * los requisitos seleccionados
		 */
		int [] arrayPreguntasValidas = new int[mapaPreguntas.size()];
		int n = 0;
		for (Iterator iterator = mapaPreguntas.keySet().iterator(); iterator
		.hasNext();) {
			String clave = (String)iterator.next(); 
			Pregunta p = mapaPreguntas.get(clave);
			arrayPreguntasValidas[n] = p.getCodPreg();
			n++;		
		}
		
		
		/*
		 * De todas las preguntas que cumplen los requisitos obtenemos aleatoriamente con la clase Random cada pregunta de nuestro 
		 * array hasta alcanzar el numero de preguntas indicadas en el formulario
		 */
		List<Pregunta> preguntasExamen = new ArrayList<Pregunta>(examen.getNumPreg());
		
		/*
		 *	Tendremos un mapa para almacenar las respuestas correspondientes a cada pregunta, por lo que el tamano del mapa
		 *	sera el numero de preguntas por el numero de respuestas 
		 */
		//Map<String, List<Respuesta>> respuestasPreguntaExamen = new HashMap<String, List<Respuesta>>(examenForm.getNumPreg());
		
		int i=0;
		
		while(i<examen.getNumPreg()){
			int indice = (int)(rand.nextDouble() * mapaPreguntas.size());
			int codPreg = arrayPreguntasValidas[indice];
			Pregunta pregunta = mapaPreguntas.get(String.valueOf(codPreg));
			if(pregunta != null && !preguntasExamen.contains(pregunta)){				
				preguntasExamen.add(pregunta);
				i++;
			}
		}
		
		
		/*
		 * Generamos aleatoriamente el numero de respuestas por pregunta
		 * Que como maximo tendra el numero de respuestas de aquella pregunta que tenga en total de respuestas
		 * un valor mÃ­nimo
		 */
		int maxResp = Integer.MAX_VALUE;
		for (Iterator iterator = preguntasExamen.iterator(); iterator.hasNext();) {
			Pregunta p = (Pregunta) iterator.next();
			List<Respuesta> todasRespuestasPregunta = respuestaDao.findRespuestasPregunta(p);		
			if(todasRespuestasPregunta.size() < maxResp){
				maxResp = p.getRespuestas().size();
			}			
		}
		
		int numResp = (int)(rand.nextDouble() * maxResp);
		if(examen.getNumResp() > maxResp){
			examen.setNumResp(maxResp);
		}

		
		/*
		 * Este conjunto contendra todas las respuestas que iran en el examen
		 * Cada respuesta esta asociado internamente con su respectiva pregunta
		 */
		Set<Respuesta> respuestasPreguntaExamen = new HashSet<Respuesta>(examen.getNumPreg()*examen.getNumResp());
		
		
		Set<Respuesta> respuestasValidas = new HashSet<Respuesta>(examen.getNumPreg()*examen.getNumResp());
		
		for (Iterator iterator = preguntasExamen.iterator(); iterator.hasNext();) {
			Pregunta p = (Pregunta) iterator.next();
			
			List<Respuesta> todasRespuestasPregunta = respuestaDao.findRespuestasPregunta(p);			
			Map<String,Respuesta> mapaTodasRespuestasPregunta = new HashMap<String, Respuesta>(todasRespuestasPregunta.size());			
			int[] respPosibles = new int[todasRespuestasPregunta.size()];
			Set<Respuesta> respuestasPosibles = new HashSet<Respuesta>(todasRespuestasPregunta.size());
			
			int indiceResp = 0;
			for (Iterator iterator2 = todasRespuestasPregunta.iterator(); iterator2
					.hasNext();) {
				Respuesta r = (Respuesta) iterator2.next();
				
				if(r.isEsCorrecta()){
					respuestasValidas.add(r);
				}else{
					mapaTodasRespuestasPregunta.put(String.valueOf(r.getCodResp()), r);
					//respuestasPosibles[indiceResp] = r.getCodResp();
					respPosibles[indiceResp] = r.getCodResp();
					respuestasPosibles.add(r);
					indiceResp++;
				}
				//indiceResp++;

			}
			
			int y=0;	
			while(y<examen.getNumResp()-1){
				int indice = (int)(rand.nextDouble() * respuestasPosibles.size());
				int codResp = respPosibles[indice];
				Respuesta resp = mapaTodasRespuestasPregunta.get(String.valueOf(codResp));
				if(resp != null && !respuestasValidas.contains(resp)){
					respuestasValidas.add(resp);
					//respuestasPreguntaExamen.add(resp);
					y++;
				}
			}
			//respuestasPreguntaExamen.put(String.valueOf(p.getCodPreg()), respuestasValidas);
		}		
		
		
		examen.setPreguntas(preguntasExamen);
		//examen.setRespuestasPreguntasExamen(respuestasPreguntaExamen);
		examen.setRespuestas(new ArrayList<Respuesta>(respuestasValidas));
		
		
		return examen;
	}

}
